Using Sequence Grabber Components
You can use the sequence grabber component to play captured data for the user or to save captured data in a QuickTime movie. The sequence grabber component provides functions that give your application precise control over the display of the captured data.This section describes how to use the basic sequence grabber component functions as well as the functions that allow you to configure video and sound channels.
Sequence grabber components are standard components that are managed by the Component Manager. See the chapter "Component Manager" in Inside Macintosh: More Macintosh Toolbox for more information about the Component Manager and about how to use components.
Apple has defined a component type value for sequence grabber components--that type value is
'barg'
. You can use the following constant to specify this type value.
#define SeqGrabComponentType 'barg' /* sequence grabber component type */Apple has defined a functional interface for basic sequence grabber components. For information about the functions a sequence grabber component may support, see "Sequence Grabber Component Functions," which begins on page 5-22.You can use the following constants to refer to the request codes for each of the functions that a sequence grabber component may support.
enum { /* selectors for basic sequence grabber component functions */ kSGInitializeSelect = 0x1; /* SGInitialize */ kSGSetDataOutputSelect = 0x2; /* SGSetDataOutput */ kSGGetDataOutputSelect = 0x3; /* SGGetDataOutput */ kSGSetGWorldSelect = 0x4; /* SGSetGWorld */ kSGGetGWorldSelect = 0x5; /* SGGetGWorld */ kSGNewChannelSelect = 0x6; /* SGNewChannel */ kSGDisposeChannelSelect = 0x7; /* SGDisposeChannel */ kSGStartPreviewSelect = 0x10; /* SGStartPreview */ kSGStartRecordSelect = 0x11; /* SGStartRecord */ kSGIdleSelect = 0x12; /* SGIdle */ kSGStopSelect = 0x13; /* SGStop */ kSGPauseSelect = 0x14; /* SGPause */ kSGPrepareSelect = 0x15; /* SGPrepare */ kSGReleaseSelect = 0x16; /* SGRelease */ kSGGetMovieSelect = 0x17; /* SGGetMovie */ kSGSetMaximumRecordTimeSelect = 0x18; /* SGSetMaximumRecordTime */ kSGGetMaximumRecordTimeSelect = 0x19; /* SGGetMaximumRecordTime */ kSGGetStorageSpaceRemainingSelect= 0x1a; /* SGGetStorageSpaceRemaining */ kSGGetTimeRemainingSelect = 0x1b; /* SGGetTimeRemaining */ kSGGrabPictSelect = 0x1c; /* SGGrabPict */ kSGGetLastMovieResIDSelect = 0x1d; /* SGGetLastMovieResID */ kSGSetFlagsSelect = 0x1e; /* SGSetFlags */ kSGGetFlagsSelect = 0x1f; /* SGGetFlags */ kSGSetDataProcSelect = 0x20; /* SGSetDataProc */ kSGNewChannelFromComponentSelect = 0x21; /* SGNewChannelFromComponent */ kSGDisposeDeviceListSelect = 0x22; /* SGDisposeDeviceList */ kSGAppendDeviceListToMenuSelect = 0x23; /* SGAppendDeviceListToMenu */ kSGSetSettingsSelect = 0x24; /* SGSetSettings */ kSGGetSettingsSelect = 0x25; /* SGGetSettings */ kSGGetIndChannelSelect = 0x26; /* SGGetIndChannel */ kSGUpdateSelect = 0x27; /* SGUpdate */ kSGGetPauseSelect = 0x28; /* SGGetPause */ kSGSettingsDialogSelect = 0x29; /* SGSettingsDialog */ kSGGetAlignmentProcSelect = 0x2A; /* SGGetAlignmentProc */ kSGSetChannelSettingsSelect = 0x2B; /* SGSetChannelSettings */ kSGGetChannelSettingsSelect = 0x2C; /* SGGetChannelSettings */ /* selectors for common channel configuration functions */ kSGCSetChannelUsageSelect = 0x80; /* SGCSetChannelUsage */ kSGCGetChannelUsageSelect = 0x81; /* SGCGetChannelUsage */ kSGCSetChannelBoundsSelect = 0x82; /* SGCSetChannelBounds */ kSGCGetChannelBoundsSelect = 0x83; /* SGCGetChannelBounds */ kSGCSetChannelVolumeSelect = 0x84; /* SGCSetChannelVolume */ kSGCGetChannelVolumeSelect = 0x85; /* SGCGetChannelVolume */ kSGCGetChannelInfoSelect = 0x86; /* SGCGetChannelInfo */ kSGCSetChannelPlayFlagsSelect = 0x87; /* SGCSetChannelPlayFlags */ kSGCGetChannelPlayFlagsSelect = 0x88; /* SGCGetChannelPlayFlags */ kSGCSetChannelMaxFramesSelect = 0x89; /* SGCSetChannelMaxFrames */ kSGCGetChannelMaxFramesSelect = 0x8a; /* SGCGetChannelMaxFrames */ kSGCSetChannelRefConSelect = 0x8b; /* SGCSetChannelRefCon */ kSGCSetChannelClipSelect = 0x8C; /* SGCSetChannelClip */ kSGCGetChannelClipSelect = 0x8D; /* SGCGetChannelClip */ kSGCGetChannelSampleDescriptionSelect = 0x8E; /* SGCGetChannelSampleDescription */ kSGCGetChannelDeviceListSelect = 0x8F; /* SGCGetChannelDeviceList */ kSGCSetChannelDeviceSelect = 0x90; /* SGCSetChannelDevice */ kSGCSetChannelMatrixSelect = 0x91; /* SGCSetChannelMatrix */ kSGCGetChannelMatrixSelect = 0x92; /* SGCGetChannelMatrix */ kSGCGetChannelTimeScaleSelect = 0x93; /* SGCGetChannelTimeScale */ /* selectors for video channel configuration functions */ kSGCGetSrcVideoBoundsSelect = 0x100; /* SGCGetSrcVideoBounds */ kSGCSetVideoRectSelect = 0x101; /* SGCSetVideoRect */ kSGCGetVideoRectSelect = 0x102; /* SGCGetVideoRect */ kSGCGetVideoCompressorTypeSelect = 0x103; /* SGCGetVideoCompressorType */ kSGCSetVideoCompressorTypeSelect = 0x104; /* SGCSetVideoCompressorType */ kSGCSetVideoCompressorSelect = 0x105; /* SGCSetVideoCompressor */ kSGCGetVideoCompressorSelect = 0x106; /* SGCGetVideoCompressor */ kSGCGetVideoDigitizerComponentSelect = 0x107; /* SGCGetVideoDigitizerComponent */ kSGCSetVideoDigitizerComponentSelect = 0x108; /* SGCSetVideoDigitizerComponent */ kSGCVideoDigitizerChangedSelect = 0x109; /* SGCVideoDigitizerChanged */ kSGCSetVideoBottlenecksSelect = 0x10a; /* SGCSetVideoBottlenecks */ kSGCGetVideoBottlenecksSelect = 0x10b; /* SGCGetVideoBottlenecks */ kSGCGrabFrameSelect = 0x10c; /* SGCGrabFrame */ kSGCGrabFrameCompleteSelect = 0x10d; /* SGCGrabFrameComplete */ kSGCDisplayFrameSelect = 0x10e; /* SGCDisplayFrame */ kSGCCompressFrameSelect = 0x10f; /* SGCCompressFrame */ kSGCCompressFrameCompleteSelect = 0x110; /* SGCCompressFrameComplete */ kSGCAddFrameSelect = 0x111; /* SGCAddFrameSelect */ kSGCTransferFrameForCompressSelect = 0x112; /* SGCTransferFrameForCompress */ kSGCSetCompressBufferSelect = 0x113; /* SGCSetCompressBuffer */ kSGCGetCompressBufferSelect = 0x114; /* SGCGetCompressBuffer */ kSGCGetBufferInfoSelect = 0x115; /* SGCGetBufferInfo */ kSGCSetUseScreenBufferSelect = 0x116; /* SGCSetUseScreenBuffer */ kSGCGetUseScreenBufferSelect = 0x117; /* SGCGetUseScreenBuffer */ kSGCGrabCompressCompleteSelect = 0x118; /* SGCGrabCompressComplete */ kSGCDisplayCompressSelect = 0x119; /* SGCDisplayCompress */ kSGCSetFrameRateSelect = 0x11A; /* SGCSetFrameRate */ kSGCGetFrameRateSelect = 0x11B; /* SGCGetFrameRate */ /* selectors for sound channel configuration functions */ kSGCSetSoundInputDriverSelect = 0x100;/* SGCSetSoundInputDriver */ kSGCGetSoundInputDriverSelect = 0x101;/* SGCGetSoundInputDriver */ kSGCSoundInputDriverChangedSelect = 0x102; /* SGCSoundInputDriverChanged */ kSGCSetSoundRecordChunkSizeSelect = 0x103; /* SGCSetSoundRecordChunkSize */ kSGCGetSoundRecordChunkSizeSelect = 0x104; /* SGCGetSoundRecordChunkSize */ kSGCSetSoundInputRateSelect = 0x105; /* SGCSetSoundInputRate */ kSGCGetSoundInputRateSelect = 0x106; /* SGCGetSoundInputRate */ kSGCSetSoundInputParametersSelect = 0x107; /* SGCSetSoundInputParameters */ kSGCGetSoundInputParametersSelect = 0x108; /* SGCGetSoundInputParameters */ /* selectors for utility functions provided to channel components */ kSGWriteMovieData = 0x100; /* SGWriteMovieData */ kSGAddFrameReferenceSelect = 0x101; /* SGAddFrameReference */ kSGGetNextFrameReferenceSelect = 0x102; /* SGGetNextFrameReference */ kSGGetTimeBaseSelect = 0x103; /* SGGetTimeBase */ kSGSortDeviceListSelect = 0x104; /* SGSortDeviceList */ kSGAddMovieDataSelect = 0x105; /* SGAddMovieData */ kSGChangedSourceSelect = 0x106; /* SGChangedSource */ };Previewing and Recording Captured Data
You can use sequence grabber components in two ways: to play digitized data for the user or to save captured data in a QuickTime movie. The process of displaying data that is to be captured is called previewing; saving captured data in a movie is called recording. You can use previewing to allow the user to prepare to make a recording. If you do so, your application can move directly from the preview operation to a record operation, without stopping the process.Previewing
Previewing captured data involves playing that data for the user as it is captured. For video data, this means displaying the video images on the computer screen. For audio data, this means playing the sound through the computer's sound system. The following paragraphs outline the steps you must follow to preview captured data.
See the sample program in Listing 5-1 on page 5-10 for an example of the preview operation.
- First, you must open a connection to the sequence grabber component. Use the Component Manager's
OpenDefaultComponent
orOpenComponent
function.- Once you have a connection to a sequence grabber component, you must configure the component for the preview operation. Use the
SGSetGWorld
function (described on page 5-27) to set the graphics world in which the preview is to be displayed. Allocate the appropriate channels by calling theSGNewChannel
function (described on page 5-29). You must call this function once for each channel to be used by the sequence grabber component. Use theSGSetChannelUsage
function (described on page 5-56) to specify that each channel is to be used for previewing. You can then use the appropriate channel configuration functions to prepare the channel for the preview operation. For video channels, use the functions discussed in "Working With Video Channels" beginning on page 5-73. For sound channels, use the functions discussed in "Working With Sound Channels" beginning on page 5-88.- You start the preview operation by calling the
SGStartPreview
function (see page 5-35). The sequence grabber component then begins collecting data from the channels that you have created and plays that data appropriately. You can pause and restart the preview by calling theSGPause
function (see page 5-38). Use theSGStop
function (see page 5-38) to stop the preview. During the preview operation, be sure to call theSGIdle
function (see page 5-36) frequently, so that the sequence grabber and its channels can perform the operation.- When you are done previewing, you can start recording or close your connection to the sequence grabber component. When you close the sequence grabber component, it automatically disposes of the channels you created.
Recording
During a record operation, a sequence grabber component collects the data it captures and formats that data into a QuickTime movie. During a record operation, the sequence grabber can also play the captured data for the user. However, the sequence grabber tries to prevent the playback from interfering with the quality of the recording process.The following paragraphs discuss the steps you must follow to record captured data.
- As with a preview operation, your application must establish a
connection to a sequence grabber component. Use the Component
Manager'sOpenDefaultComponent
orOpenComponent
function.- Once you have a connection to a sequence grabber component, you must configure the component for the record operation. Use the
SGSetGWorld
function (see page 5-27) to set the graphics world in which the data is to be displayed. Allocate the appropriate channels by calling theSGNewChannel
function (see page 5-29). You must call this function once for each channel to be used by the sequence grabber component. Use theSGSetChannelUsage
function (see page 5-56) to specify that each channel is to be used for recording. At this time, you can specify whether the sequence grabber is to play that channel's data while recording. You can then use the appropriate channel configuration functions to prepare the channel for the record operation. For video channels, use the functions discussed in "Working With Video Channels" beginning on page 5-73. For sound channels, use the functions discussed in "Working With Sound Channels" beginning on page 5-88.- You must specify a movie file for use by the sequence grabber during the record operation. Use the
SGSetDataOutput
function (see page 5-24) to specify this movie file. This function also allows you to control whether the sequence grabber adds the movie resource to the movie file and whether it replaces existing data or appends the new movie to the file.- You can limit the amount of data that is captured during a record operation. The
SGSetMaximumRecordTime
function (see page 5-51) establishes a time limit for the record operation. TheSGSetChannelMaxFrames
function (see page 5-60) limits the number of frames of data that the sequence grabber collects from a specific channel.- You start the record operation by calling the
SGStartRecord
function (see page 5-35). The sequence grabber component then begins collecting data from the channels you have created, stores the data in a QuickTime movie, and, optionally, plays that data appropriately. You can pause and restart the record process by calling theSGPause
function (see page 5-38). During the record operation, be sure to call theSGIdle
function (see page 5-36) frequently, so that the sequence grabber and its channels can perform the operation. Use theSGStop
function (see page 5-38) to stop recording. At this time, the sequence grabber saves the movie in your movie file, if you have chosen to do so.- When you are done recording, you can go back to previewing or close your connection to the sequence grabber component. When you close the sequence grabber component, it automatically disposes of the channels you created as well as any movies it has created.
Playing Captured Data and Saving It in a QuickTime Movie
This section supplies a sample program that shows how to use a sequence grabber component to preview and record captured data. The program is divided into groups of functions that do the following tasks:
- initialization
- video and sound channel creation
- sequence preview
- capture of sound and video sequences
- drawing over video frames during a capture operation
Initializing a Sequence Grabber Component
Listing 5-1 provides a sample function that creates and initializes a default sequence grabber component for a specified window (using theOpenDefaultComponent
andSGInitialize
functions, respectively). It then sets the graphics world of the sequence grabber component to the specified window with theSGSetGWorld
function. Note that theCloseComponent
function is called for housekeeping purposes in case the sequence grabber component fails. For more onOpenDefaultComponent
andCloseComponent
, see the chapter "Component Manager" in Inside Macintosh: More Macintosh Toolbox. For details onSGInitialize
andSGSetGWorld
, see page 5-23 and page 5-27, respectively.Listing 5-1 Initializing a sequence grabber component
SeqGrabComponent MakeSequenceGrabber (WindowPtr aWindow) { SeqGrabComponent anSG; OSErr err = noErr; /* open up the default sequence grabber */ anSG = OpenDefaultComponent (SeqGrabComponentType, 0); if (anSG) { /* initialize the default sequence grabber component */ err = SGInitialize (anSG); if (!err) { /* set the sequence grabber's graphics world to the specified window */ err = SGSetGWorld (anSG, (CGrafPtr) aWindow, nil); } } if (err && anSG) { /* clean up on failure */ CloseComponent (anSG); anSG = nil; } return anSG; }Creating a Sound Channel and a Video Channel
Listing 5-2 supplies a sample function that attempts to create a video channel and a sound channel for the sequence grabber component that was created in Listing 5-1. The boundaries of the video channel are set to the specifications of thebounds
parameter. The channel's usage is always set to allow previewing. If the value of thewillRecord
parameter istrue
, then the usage of the channel is set to allow recording also.The
SGNewChannel
function (described on page 5-29) uses theVideoMediaType
constant to create a video channel and theSoundMediaType
constant to create a sound channel. TheSGSetChannelBounds
function (described on page 5-62) specifies the boundaries of the video channel. TheSGSetChannelUsage
function (described on page 5-56) specifies whether the video and the sound channels are used for preview or record operations. TheSGDisposeChannel
function (described on page 5-32) cleans up upon failure for each of the channels.Listing 5-2 Creating a sound channel and a video channel
void MakeGrabChannels (SeqGrabComponent anSG, SGChannel *videoChannel, SGChannel *soundChannel, const Rect *bounds, Boolean willRecord) { OSErr err; long usage; /* figure out the usage */ usage = seqGrabPreview; /* always previewing */ if (willRecord) usage |= seqGrabRecord; /* sometimes recording */ /* create a video channel */ err = SGNewChannel (anSG, VideoMediaType, videoChannel); if (!err) { /* set boundaries for new video channel */ err = SGSetChannelBounds (*videoChannel, bounds); /* set usage for new video channel */ if (!err) err = SGSetChannelUsage (*videoChannel, usage | seqGrabPlayDuringRecord); if (err) { /* clean up on failure */ SGDisposeChannel (anSG, *videoChannel); *videoChannel = nil; } } /* create a sound channel */ err = SGNewChannel (anSG, SoundMediaType, soundChannel); if (!err) { /* set usage of new sound channel */ err = SGSetChannelUsage (*soundChannel, usage); if (err) { /* clean up on failure */ SGDisposeChannel(anSG, *soundChannel); *soundChannel = nil; } } }Previewing Sound and Video Sequences in a Window
Listing 5-3 shows how to use the sequence grabber component to preview sound and video sequences in a window. Clicking the content area of the window causes the sequence grabber to pause until the mouse button is released.The Image Compression Manager's
GetBestDeviceRect
function helps you determine the best monitor for the window. TheSGStartPreview
function (described on page 5-35) begins the preview of the sound and video sequences. TheSGIdle
function (described on page 5-36) grants the sequence grabber component the time it needs to preview data. TheSGUpdate
function (described on page 5-37) informs the sequence grabber of the update event. The Window Manager'sBeginUpdate
andEndUpdate
functions respond to the event. TheSGPause
function (described on page 5-38) instructs the sequence grabber to suspend and resume its preview operation. In this example, it is used to suspend the preview operation while the mouse button is held down. Finally, theSGStop
function (described on page 5-38) halts the action of the sequence grabber component. The Component Manager'sCloseComponent
function closes the component connection. The Window Manager'sDisposeWindow
function disposes of the window.Listing 5-3 Previewing sound and video sequences in a window
void CheckError(OSErr error, Str255 displayString) { if (error == noErr) return; if (displayString[0] > 0) DebugStr(displayString); ExitToShell(); } Boolean IsQuickTimeInstalled (void) { short error; long result; error = Gestalt (gestaltQuickTime, &result); return (error == noErr); } void initialize (void) { OSErr err; InitGraf (&qd.thePort); InitFonts (); InitWindows (); InitMenus (); TEInit (); InitDialogs (nil); MaxApplZone(); if (!IsQuickTimeInstalled()) CheckError(-1,"\pPlease install QuickTime and try again."); err = EnterMovies (); CheckError(err,"\pUnable to initialize Movie Toolbox."); } WindowPtr makeWindow(void) { WindowPtr aWindow; Rect windowRect = {0, 0, 120, 160}; Rect bestRect; /* figure out the best monitor for the window */ GetBestDeviceRect (nil, &bestRect); /* put the window in the top left corner of that monitor */ OffsetRect(&windowRect, bestRect.left + 10, bestRect.top + 50); /* create the window */ aWindow = NewCWindow (nil, &windowRect, "\pGrabber", true, noGrowDocProc, (WindowPtr)-1, true, 0); /* and set the port to the new window */ SetPort(aWindow); return aWindow; } main (void) { WindowPtr theWindow; SeqGrabComponent theSG; SGChannel videoChannel, soundChannel; Boolean done = false; OSErr err; initialize(); theWindow = makeWindow(); theSG = makeSequenceGrabber(theWindow); if (!theSG) return; makeGrabChannels(theSG, &videoChannel, &soundChannel, &theWindow->portRect, false); if ((videoChannel == nil) && (soundChannel == nil)) CheckError(-1,"\pNo sound or video available."); err = SGStartPreview(theSG); CheckError(err, "\pCan't start preview"); while (!done) { AlignmentProcRecord alignProc; short part; WindowPtr whichWindow; EventRecord theEvent; GetNextEvent(everyEvent, &theEvent); switch (theEvent.what) { case nullEvent: /* give the sequence grabber time */ err = SGIdle (theSG); if (err) done = true; break; case updateEvt:if (theEvent.message == (long)theWindow) { /* inform the sequence grabber of the update */ SGUpdate(theSG,((WindowPeek) theWindow)->updateRgn); /* and swallow the update event */ BeginUpdate(theWindow); EndUpdate(theWindow); } break; case mouseDown:part = FindWindow (theEvent.where, &whichWindow); if (whichWindow != theWindow) break; switch (part) { case inContent: /* pause until mouse button is released */ SGPause (theSG, true); while (StillDown()) ; SGPause(theSG, false); break; case inGoAway: done = TrackGoAway (theWindow, theEvent.where); break; case inDrag: /* pause when dragging window so video doesn't draw in the wrong place */ SGPause (theSG, true); SGGetAlignmentProc (theSG, &alignProc); DragAlignedWindow (theWindow, theEvent.where, &screenBits.bounds, nil, &alignProc); SGPause (theSG, false); break; } break; } } /* clean up */ SGStop (theSG); CloseComponent (theSG); DisposeWindow (theWindow); }Capturing Sound and Video Data
Listing 5-4 uses the sequence grabber component to capture ten seconds of
sound and video data. It prompts the user for the name of the file to create. TheSGSettingsDialog
function (described on page 5-45) is issued to invoke the default sound and video capture settings dialog boxes. These default dialog boxes allow the user to configure the settings for the capture operations. TheSGSetMaximumRecordTime
function (described on page 5-51) indicates how long the capture operations will last. TheSGStartRecord
function (described on page 5-35) specifies the time at which the capture operations will begin. TheSGIdle
function (described on page 5-36) grants the time needed to confirm the capture operations. Finally, theSGStop
function (described on page 5-38) and the Window Manager'sDisposeWindow
routine are called in order to complete the capture of the sequences.Listing 5-4 Capturing sound and video
main (void) { WindowPtr theWindow; CGrafPort tempPort; SeqGrabComponent theSG; SGChannel videoChannel, soundChannel; OSErr err; initialize(); theWindow = makeWindow(); theSG = makeSequenceGrabber(theWindow); if (!theSG) return; err = setGrabFile(theSG); CheckError(err, "\pNo output file"); makeGrabChannels (theSG, &videoChannel, &soundChannel, &theWindow->portRect, true); if ((videoChannel == nil) && (soundChannel == nil)) CheckError(-1,"\pNo sound or video available."); if (videoChannel) SGSettingsDialog (theSG, videoChannel, 0, nil, DoTheRightThing, nil, 0); if (soundChannel) SGSettingsDialog(theSG, soundChannel, 0, nil, DoTheRightThing, nil, 0); err = SGSetMaximumRecordTime(theSG, 10 * 60); CheckError(err, "\pCan't set max record time"); err = SGStartRecord (theSG); CheckError(err, "\pCan't start record"); while (!err) err = SGIdle (theSG); if (err == grabTimeComplete) err = noErr; CheckError(err, "\pError while recording"); err = SGStop(theSG); CheckError(err, "\pError creating movie"); CloseComponent(theSG); DisposeWindow(theWindow); }Setting Up the Video Bottleneck Functions
Listing 5-5 shows how to set up the video bottleneck functions of the sequence grabber video channel component. For more information on the video bottleneck functions, see "Utility Functions for Video Channel Callback Functions" beginning on page 5-98. Inside the main event loop in Listing 5-4, you should add the following lines after you call theSGSetMaximumRecordTime
function (described on page 5-51).Listing 5-5 Setting up the video bottleneck functions
if (videoChannel) { err = setupVideoBottlenecks (videoChannel, theWindow, &tempPort); CheckError(err, "\pCouldn't set video bottlenecks"); }Drawing Information Over Video Frames During Capture
Listing 5-6 shows how to use the video bottleneck functions of the sequence grabber video channel component to draw the letters "QT" over each video frame as it is captured.Listing 5-6 Drawing information over video frames during capture
pascal ComponentResult myGrabFrameComplete (SGChannel c, short bufferNum, Boolean *done, long refCon) { ComponentResult err; /* call the default grab-complete function */ err = SGGrabFrameComplete (c, bufferNum, done); if (*done) { /* frame is done */ CGrafPtr savePort; GDHandle saveGD; PixMapHandle bufferPM, savePM; Rect bufferRect; CGrafPtr tempPort = (CGrafPtr)refCon; /* set to our temporary port */ GetGWorld (&savePort, &saveGD); SetGWorld (tempPort, nil); /* find out about this buffer */ err = SGGetBufferInfo (c, bufferNum, &bufferPM, &bufferRect, nil, nil); if (!err) { /* set up to draw into this buffer */ savePM = tempPort->portPixMap; SetPortPix(bufferPM); /* draw some text into the buffer */ TextMode (srcXor); MoveTo (bufferRect.right - 20, bufferRect.bottom - 14); DrawString ("\pQT"); TextMode(srcOr); /* restore temporary port */ SetPortPix (savePM); } SetGWorld (savePort, saveGD); } return err; } OSErr setupVideoBottlenecks (SGChannel videoChannel, WindowPtr w, CGrafPtr tempPort) { OSErr err; err = SGSetChannelRefCon (videoChannel, (long)tempPort); if (!err) { VideoBottles vb; /* get the current bottlenecks */ vb.procCount = 9; err = SGGetVideoBottlenecks (videoChannel, &vb); if (!err) { /* add our GrabFrameComplete function */ vb.grabCompleteProc = myGrabFrameComplete; err = SGSetVideoBottlenecks (videoChannel, &vb); /* set up the temporary port */ OpenCPort (tempPort); /* create a temporary port for drawing */ SetRectRgn (tempPort->visRgn, -32000, -32000, 32000, 32000); /* with a wide open visible and clip region . . . */ CopyRgn (tempPort->visRgn, tempPort->clipRgn); /* so that you can use it in any video buffer */ PortChanged ((GrafPtr)tempPort); /* tell QuickDraw about the changes */ } } return err; }
Subtopics
- Previewing and Recording Captured Data
- Previewing
- Recording
- Playing Captured Data and Saving It in a QuickTime Movie
- Initializing a Sequence Grabber Component
- Creating a Sound Channel and a Video Channel
- Previewing Sound and Video Sequences in a Window
- Capturing Sound and Video Data
- Setting Up the Video Bottleneck Functions
- Drawing Information Over Video Frames During Capture
Main | Top of Section | What's New | Apple Computer, Inc. | Find It | Feedback | Help